package com.ht.aems.eas;

import com.ht.aems.ucp.AvcDevKeys;
import com.ht.aems.ucp.UcpFacade;
import com.ht.psplan.PlanCommInfo;
import com.ht.psplan.PlanInfo;
import com.ht.psplan.PlanPersistLayer;
import com.ht.psplan.PlanPlFactory;
import devmodel.MapObject;
import hhh.remoteService.utils.ServiceQuery;
import org.apache.log4j.Logger;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * @author Dong Shufeng
 *         Date: 2009-5-26
 */
public class RemoteEasFacade extends UnicastRemoteObject implements EasFacade, AvcDevKeys {
    private static Logger log = Logger.getLogger(RemoteEasFacade.class);

    private AvcExecutor avcExecutor = new AvcExecutor();
    private int mode;
    static RemoteEasFacade instance;

    static {
        try {
            instance = new RemoteEasFacade();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    public RemoteEasFacade() throws RemoteException {
        setMode(AVC_MODE_ONLINE);
    }

    public void makeCommand() throws RemoteException {
        UcpFacade deviceService = (UcpFacade) ServiceQuery.getService(UcpFacade.class);
        if (deviceService == null) {
            log.warn("Controllable Device Service is not found, no command would be sent.");
            return;
        }
        try {
            log.info("Sending command start...");
            avcExecutor.setvControllableDevs(deviceService.getVControllableDevs());
            avcExecutor.setqControllableDevs(deviceService.getQControllableDevs());
            avcExecutor.setAllVDevs(deviceService.getAllVDevs());
            List<MapObject> allV = deviceService.getAllVDevs();
            List<MapObject> plants = new ArrayList<MapObject>();
            for (MapObject dev : allV)
                //if (dev.getType().equals(TYPE_PLANT))
                plants.add(dev);
            avcExecutor.setAllVDevs(plants);
            System.out.println("VControllabeldev size = " + avcExecutor.getvControllableDevs().size());
            System.out.println("QControllabeldev size = " + avcExecutor.getqControllableDevs().size());
            System.out.println("allVDev size = " + avcExecutor.getAllVDevs().size());

            Command command = avcExecutor.doAvc();
            log.info("Making command finished.");
            if (mode == STATUS_REMOTE) {
                sendPlantCmd(command);
                sendStationCmd(command);//todo:
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.warn("Exception occured when sending command: " + e);
        }
    }

    public void reloadAvcPoints() throws RemoteException {
        avcExecutor.reloadAvcPoints();
    }

    public void makeComman() throws RemoteException {
        System.out.println("dooooooooooooooooooo");
    }

    public void sendStationCmd(Command command) throws RemoteException {
        UcpFacade commandProxy = (UcpFacade) ServiceQuery.getService(UcpFacade.class);
        if (commandProxy == null) {
            log.warn("Failed to send command: Station Command Proxy is not found");
            return;
        }
        List<MapObject> devices = new ArrayList<MapObject>(300);//todo: just good for sh
        for (MapObject d : avcExecutor.getvControllableDevs())
            if (d.getType() != null && (d.getType().equals(TYPE_BUS) || d.getType().equals(TYPE_AREA_BUS)) && command.getAnalogCommand().containsKey(d.getId()))
                devices.add(d);
        for (MapObject d : avcExecutor.getqControllableDevs())
            if (d.getType() != null && (d.getType().equals(TYPE_TRANSFORMER) || d.getType().equals(TYPE_AREA_TRANSFORMER)) && command.getAnalogCommand().containsKey(d.getId()))
                devices.add(d);

        String[] keys = new String[devices.size()];
        double[] values = new double[devices.size()];
        Double[] meases = new Double[devices.size()];
        int index = 0;
        for (MapObject d : devices) {
            keys[index] = d.getId();
            values[index] = command.getAnalogCommand().get(d.getId());
            meases[index] = command.getOriginalAnalog().get(d.getId());
            log.info("Send... " + d.getName() + ",Value is " + values[index] + ", Measure is " + meases[index]);
            index++;
        }

        if (index > 0)
            commandProxy.sendAnalogCommand(keys, values, meases);
        else
            log.info("No station command is needed to send.");
        log.info("Sending station command end.");
    }

    public void sendPlantCmd(Command command) throws RemoteException {
        UcpFacade commandProxy = (UcpFacade) ServiceQuery.getService(UcpFacade.class);
        if (commandProxy == null) {
            log.warn("Failed to send command: Plant Command Proxy is not found");
            return;
        }
        List<MapObject> plants = new ArrayList<MapObject>(15);//todo: just good for sh
        System.out.println("commands: ");
        System.out.println(command.getAnalogCommand());
        for (MapObject d : avcExecutor.getvControllableDevs())
            if (d.getType() != null && d.getType().equals(TYPE_PLANT) && command.getAnalogCommand().containsKey(d.getId()))
                plants.add(d);

        String[] keys = new String[plants.size()];
        double[] values = new double[plants.size()];
        Double[] meases = new Double[plants.size()];
        int index = 0;

        for (MapObject d : plants) {
            keys[index] = d.getId();
            values[index] = command.getAnalogCommand().get(d.getId());
            meases[index] = command.getOriginalAnalog().get(d.getId());
            log.info("Send... " + d.getId() + ",Value is " + values[index] + ", Measure is " + meases[index]);
            index++;
        }
        //send analog command, there are only analog commands in shang
        if (index > 0)
            commandProxy.sendAnalogCommand(keys, values, meases);
        else
            log.info("No plant command is needed to send.");
        log.info("Sending plant command end.");
    }

    public void loadPlans() throws RemoteException {
        log.info("Loading plans start...");
        PlanPersistLayer planPersistLayer = PlanPlFactory.getPersistLayer();
        if (planPersistLayer == null) {
            log.warn("No plan persist layer is found!");
            return;
        }
        int size = (avcExecutor.getvControllableDevs() != null ? avcExecutor.getvControllableDevs().size() : 0)
                + (avcExecutor.getqControllableDevs() != null ? avcExecutor.getqControllableDevs().size() : 0);
        List<MapObject> deviceIdsNeedPlan = new ArrayList<MapObject>(size);
        if (avcExecutor.getvControllableDevs() != null)
            deviceIdsNeedPlan.addAll(avcExecutor.getvControllableDevs());
        if (avcExecutor.getqControllableDevs() != null)
            deviceIdsNeedPlan.addAll(avcExecutor.getqControllableDevs());
        reloadPlans(deviceIdsNeedPlan, planPersistLayer);
        log.info("Loading plans end.");
    }

    public void loadCalModel() {
        RtdbUtil.loadCalModel();
    }

    public void loadDeviceIds() {
        RtdbUtil.loadDeviceIds();
    }

    protected void reloadPlans(List<MapObject> devs, PlanPersistLayer planPersistLayer) {
        EasSysModel.INSTANCE.getPlans().clear();
        String[] ids = new String[devs.size()];
        int i = 0;
        for (MapObject d : devs)
            ids[i++] = d.getId();
        Map<String, PlanCommInfo> planCommInfos = planPersistLayer.getPlan(ids);
        if (planCommInfos == null) {
            log.warn("Plan CommInfo is not found");
            return;
        }
        //PlanInfo planInfo = planPersistLayer.getPlanInfo(planCommInfo.getId(), new Date());
        Map<String, PlanInfo> planInfos = planPersistLayer.getPlanInfo(planCommInfos, new Date());
        if (planInfos == null) {
            log.warn("No plan is found in database.");
            return;
        }
        EasSysModel.INSTANCE.getPlans().putAll(planInfos);
    }

    public void setMode(int mode) {
        this.mode = mode;
    }

    public int getMode() {
        return mode;
    }

    public void setOpfObj(String objectName) throws RemoteException {
        avcExecutor.getOpfExecutor().setOpfObj(objectName);
    }
}
